package yxy.banana.socket.controller.client;

import yxy.apple.protobuf.Constants;
import yxy.apple.protobuf.Message.Parcal;
import yxy.apple.protobuf.internal.router.Message.RegistryRequest;
import yxy.apple.protobuf.internal.router.Message.RegistryResponse;
import yxy.apple.util.IDGenerator;
import yxy.banana.socket.NetworkElement;
import yxy.banana.socket.controlled.ControlledHandler;
import yxy.banana.socket.receiver.Observer;
import yxy.banana.socket.receiver.Receivable;

public abstract class ClientRegistryController<H extends ControlledHandler> extends ClientHeartbeatController<H> {

	private boolean registered = false;
	private boolean registering = false;

	public boolean registered() {
		return this.registered;
	}

	public boolean registering() {
		return this.registering;
	}

	/**
	 * 发起注册，一般情况下应在actived回调后进行
	 * 
	 * @param exclusion
	 * @throws Exception
	 */
	public void register(int timeout) throws Exception {
		if (this.registering || this.registered) {
			new RuntimeException("It is registering or registered already!");
		}
		this.registering = true;
		RegistryRequest.Builder builder = RegistryRequest.newBuilder();
		builder.setSystem(this.handler().system());
		builder.setCluster(this.handler().cluster());
		RegistryRequest request = builder.build();
		Receivable receiver = new Receivable() {
			@Override
			public void receive(Parcal parcal) {
				boolean result = false;
				if (parcal.getProto() == Constants.ControlProto.RegistryResponse) {
					try {
						RegistryResponse response = RegistryResponse.parseFrom(parcal.getData());
						result = response.getResult();
					} catch (Exception e) {
						ClientRegistryController.this.caught(e);
					}
				} else {
					ClientRegistryController.this.drop(parcal, DroppedReason.UnknownProto);
				}
				ClientRegistryController.this.callback(result);
			}

			@Override
			public void exipred(String tag) {
				ClientRegistryController.this.callback(false);
			}
		};
		try {
			String tag = IDGenerator.nextUUID();
			Observer.shared.observe(tag, timeout, receiver);
			long s = NetworkElement.value(this.handler().system(), this.handler().cluster(), this.handler().channel());
			long d = 0;
			this.handler().send(tag, s, d, Constants.ControlProto.RegistryRequest, request);
		} catch (Exception e) {
			this.registering = false;
			throw e;
		}
	}

	private void callback(boolean result) {
		this.registered = result;
		this.registering = false;
		this.registered(result);
	}

	/**
	 * 注册请求得到回应后回调
	 * 
	 * @param result
	 */
	protected abstract void registered(boolean result);

}
